package de.jmda.gen.java.impl;

import static de.jmda.core.util.StringUtil.sb;

import java.util.ArrayList;
import java.util.List;

import de.jmda.core.util.StringUtil;
import de.jmda.gen.Generator;
import de.jmda.gen.GeneratorException;
import de.jmda.gen.impl.AbstractCompoundGenerator;
import de.jmda.gen.java.InstanceFieldDeclarationsGenerator;
import de.jmda.gen.java.InstanceMethodDeclarationsGenerator;
import de.jmda.gen.java.StaticPartsGenerator;
import de.jmda.gen.java.TypeBodyGenerator;

public class DefaultTypeBodyGenerator
		extends AbstractCompoundGenerator
		implements TypeBodyGenerator
{
	public final static String DEFAULT_TYPE_BODY =
			"{" + System.lineSeparator() + "}";

	private StaticPartsGenerator staticPartsGenerator;
	private InstanceFieldDeclarationsGenerator instanceFieldDeclarationsGenerator;
	private InstanceMethodDeclarationsGenerator instanceMethodDeclarationsGenerator;

	public DefaultTypeBodyGenerator()
	{
		this(null, null, null);
	}

	public DefaultTypeBodyGenerator(StaticPartsGenerator staticPartsGenerator,
      InstanceFieldDeclarationsGenerator instanceFieldDeclarationsGenerator,
      InstanceMethodDeclarationsGenerator instanceMethodDeclarationsGenerator)
  {
	  super();
	  
	  setStaticPartsGenerator(staticPartsGenerator);
	  setInstanceFieldDeclarationsGenerator(instanceFieldDeclarationsGenerator);
	  setInstanceMethodDeclarationsGenerator(instanceMethodDeclarationsGenerator);

	  setComponentSeparator(DOUBLE_LINE_SEPARATOR);
  }

	@Override
  public StringBuffer generate() throws GeneratorException
  {
		StringBuffer generated = super.generate();
		
		if (StringUtil.isBlank(generated))
		{
			return sb(DEFAULT_TYPE_BODY);
		}

		return
	  		    sb("{" + System.lineSeparator())
	  		.append(generated)
	  		.append(System.lineSeparator() + "}");
  }

	/**
	 * Returns collection of <code>Generator</code>s with the return values of the
	 * following methods in the following order:
	 * <ul>
	 *   <li>{@link #getStaticPartsGenerator()}</li>
	 *   <li>{@link #getInstanceFieldDeclarationsGenerator()}</li>
	 *   <li>{@link #getInstanceMethodDeclarationsGenerator()}</li>
	 * </ul>
	 * 
	 * @see de.jmda.gen.CompoundGenerator#getGeneratorComponents()
	 */
	@Override
	public List<Generator> getGeneratorComponents()
	{
		List<Generator> result = new ArrayList<Generator>();
		
		result.add(getStaticPartsGenerator());
		result.add(getInstanceFieldDeclarationsGenerator());
		result.add(getInstanceMethodDeclarationsGenerator());

		return result;
	}

	/**
	 * @return {@link #staticPartsGenerator}, may be <code>null</code> because
	 *         static parts are optional.
	 *
	 * @see de.jmda.gen.java.TypeBodyGenerator#getStaticPartsGenerator()
	 */
	@Override
	public StaticPartsGenerator getStaticPartsGenerator()
  {
  	return staticPartsGenerator;
  }

	/**
	 * @see de.jmda.gen.java.TypeBodyGenerator#setStaticPartsGenerator(de.jmda.gen.java.StaticPartsGenerator)
	 */
	@Override
	public void setStaticPartsGenerator(StaticPartsGenerator staticPartsGenerator)
  {
  	this.staticPartsGenerator = staticPartsGenerator;
  }

	/**
	 * @return {@link #instanceFieldDeclarationsGenerator}, may be <code>null
	 *         </code> because instance fields are optional.
	 *
	 * @see de.jmda.gen.java.TypeBodyGenerator#getInstanceFieldDeclarationsGenerator()
	 */
	@Override
	public InstanceFieldDeclarationsGenerator getInstanceFieldDeclarationsGenerator()
  {
  	return instanceFieldDeclarationsGenerator;
  }

	/**
	 * @see de.jmda.gen.java.TypeBodyGenerator#setInstanceFieldDeclarationsGenerator(de.jmda.gen.java.InstanceFieldDeclarationsGenerator)
	 */
	@Override
	public void setInstanceFieldDeclarationsGenerator(
      InstanceFieldDeclarationsGenerator instanceFieldDeclarationsGenerator)
  {
  	this.instanceFieldDeclarationsGenerator = instanceFieldDeclarationsGenerator;
  }

	/**
	 * @return {@link #instanceMethodDeclarationsGenerator}, may be <code>null
	 *         </code> because instance methods are optional.
	 *
	 * @see de.jmda.gen.java.TypeBodyGenerator#getInstanceMethodDeclarationsGenerator()
	 */
	@Override
	public InstanceMethodDeclarationsGenerator getInstanceMethodDeclarationsGenerator()
  {
  	return instanceMethodDeclarationsGenerator;
  }

	/**
	 * @see de.jmda.gen.java.TypeBodyGenerator#setInstanceMethodDeclarationsGenerator(de.jmda.gen.java.InstanceMethodDeclarationsGenerator)
	 */
	@Override
	public void setInstanceMethodDeclarationsGenerator(
			InstanceMethodDeclarationsGenerator instanceMethodDeclarationsGenerator)
  {
  	this.instanceMethodDeclarationsGenerator = instanceMethodDeclarationsGenerator;
  }
	
	/**
	 * @NotNull
	 * @see de.jmda.gen.java.TypeBodyGenerator#demandStaticPartsGenerator()
	 */
	@Override
	public StaticPartsGenerator demandStaticPartsGenerator()
	{
		staticPartsGenerator = notNull(staticPartsGenerator);
	  return staticPartsGenerator;
	}

	private StaticPartsGenerator notNull(StaticPartsGenerator generator)
  {
		if (generator == null)
		{
			generator = new DefaultStaticPartsGenerator();
		}

		return generator;
  }

	@Override
  public InstanceMethodDeclarationsGenerator demandInstanceMethodDeclarationsGenerator()
  {
		instanceMethodDeclarationsGenerator = notNull(instanceMethodDeclarationsGenerator);
	  return instanceMethodDeclarationsGenerator;
  }

	@Override
  public InstanceFieldDeclarationsGenerator demandInstanceFieldDeclarationsGenerator()
  {
		instanceFieldDeclarationsGenerator = notNull(instanceFieldDeclarationsGenerator);
	  return instanceFieldDeclarationsGenerator;
  }

	private InstanceMethodDeclarationsGenerator notNull(
      InstanceMethodDeclarationsGenerator generator)
  {
		if (generator == null)
		{
			generator = new DefaultInstanceMethodDeclarationsGenerator();
		}
		return generator;
  }

	private InstanceFieldDeclarationsGenerator notNull(
      InstanceFieldDeclarationsGenerator generator)
  {
		if (generator == null)
		{
			generator = new DefaultInstanceFieldDeclarationsGenerator();
		}
		return generator;
  }
}